/*
* Demoiselle Framework
* Copyright (C) 2010 SERPRO
* ----------------------------------------------------------------------------
* This file is part of Demoiselle Framework.
*
* Demoiselle Framework is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License version 3
* along with this program; if not, see <http://www.gnu.org/licenses/>
* or write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301, USA.
* ----------------------------------------------------------------------------
* Este arquivo é parte do Framework Demoiselle.
*
* O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou
* modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
* do Software Livre (FSF).
*
* Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
* GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
* APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
* para maiores detalhes.
*
* Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
* "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
* ou escreva para a Fundação do Software Livre (FSF) Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
*/
package br.gov.frameworkdemoiselle.certificate.keystore.loader.implementation;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.util.Formatter;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.DriverNotAvailableException;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.InvalidPinException;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.KeyStoreLoader;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.KeyStoreLoaderException;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.PKCS11NotFoundException;
import br.gov.frameworkdemoiselle.certificate.keystore.loader.configuration.Configuration;
/**
* Implementação de KeyStoreLoader baseado em drivers do sistema operacional. É
* necessário informar o arquivo do driver no sistema operacional e o nome da
* API.
*/
public class DriverKeyStoreLoader implements KeyStoreLoader {
private static final String PINNUMBER_INVALID = "PIN access to token can not be null or invalid";
private static final String DRIVER_LOAD_ERROR = "Error on load a module PKCS#11";
private static final String DRIVERS_EMPTY = "No driver are available";
private static final String DRIVERS_NOT_COMPATIBLE = "No driver in the list is compatible with your hardware";
private static final String PKCS11_KEYSTORE_TYPE = "PKCS11";
private static final String PKCS11_CONTENT_CONFIG_FILE = "name = %s\nlibrary = %s";
private CallbackHandler callback;
@Override
public KeyStore getKeyStore() {
String configFile = Configuration.getInstance().getPKCS11ConfigFile();
if (configFile != null)
return this.getKeyStoreFromConfigFile(configFile);
else
return this.getKeyStoreFromDrivers();
}
public KeyStore getKeyStoreFromDriver(String driverPath) {
String driverName = driverPath.replaceAll("\\\\", "/");
int begin = driverName.lastIndexOf("/");
begin = begin <= -1 ? 0 : begin + 1;
int end = driverName.length();
driverName = driverName.substring(begin, end);
return this.getKeyStoreFromDriver(driverName, driverPath);
}
public KeyStore getKeyStoreFromDriver(String driverName, String driverPath) {
Configuration.getInstance().addDriver(driverName, driverPath);
String pkcs11ConfigSettings = null;
KeyStore keyStore = null;
pkcs11ConfigSettings = (new Formatter()).format(PKCS11_CONTENT_CONFIG_FILE, driverName, driverPath).toString();
byte[] pkcs11ConfigBytes = pkcs11ConfigSettings.getBytes();
ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11ConfigBytes);
try {
Constructor<?> construtor = Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(new Class[] { InputStream.class });
Provider pkcs11Provider = (Provider) construtor.newInstance(new Object[] { confStream });
Security.addProvider(pkcs11Provider);
confStream.close();
Method login = Class.forName("sun.security.pkcs11.SunPKCS11").getMethod("login", new Class[] { Subject.class, CallbackHandler.class });
login.invoke(Security.getProvider(pkcs11Provider.getName()), new Object[] { null, this.callback });
keyStore = KeyStore.getInstance(PKCS11_KEYSTORE_TYPE, pkcs11Provider.getName());
keyStore.load(null, null);
} catch (Exception e) {
if (e.getCause().toString().equals("javax.security.auth.login.FailedLoginException"))
throw new InvalidPinException(PINNUMBER_INVALID, e);
if (e.getCause().toString().equals("javax.security.auth.login.LoginException"))
throw new InvalidPinException(PINNUMBER_INVALID, e);
else
throw new PKCS11NotFoundException(DRIVER_LOAD_ERROR, e);
}
return keyStore;
}
private KeyStore getKeyStoreFromConfigFile(String configFile) {
KeyStore keyStore = null;
try {
Constructor<?> construtor = Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(new Class[] { String.class });
Provider pkcs11Provider = (Provider) construtor.newInstance(new Object[] { configFile });
Security.addProvider(pkcs11Provider);
Method login = Class.forName("sun.security.pkcs11.SunPKCS11").getMethod("login", new Class[] { Subject.class, CallbackHandler.class });
login.invoke(Security.getProvider(pkcs11Provider.getName()), new Object[] { null, this.callback });
keyStore = KeyStore.getInstance(PKCS11_KEYSTORE_TYPE, pkcs11Provider.getName());
keyStore.load(null, null);
} catch (Exception e) {
if (e.getCause().toString().equals("javax.security.auth.login.FailedLoginException"))
throw new InvalidPinException(PINNUMBER_INVALID, e);
if (e.getCause().toString().equals("javax.security.auth.login.LoginException"))
throw new InvalidPinException(PINNUMBER_INVALID, e);
else
throw new PKCS11NotFoundException(DRIVER_LOAD_ERROR, e);
}
return keyStore;
}
private KeyStore getKeyStoreFromDrivers() {
KeyStoreLoaderException error = new KeyStoreLoaderException(DRIVERS_NOT_COMPATIBLE);
Map<String, String> drivers = Configuration.getInstance().getDrivers();
if (drivers == null || drivers.isEmpty()) {
throw new DriverNotAvailableException(DRIVERS_EMPTY);
}
Set<String> keyDrivers = drivers.keySet();
KeyStore keyStore = null;
for (String driver : keyDrivers) {
try {
String urlDriver = drivers.get(driver);
keyStore = this.getKeyStoreFromDriver(driver, urlDriver);
break;
} catch (PKCS11NotFoundException e) {
error.addError(e);
} catch (InvalidPinException e) {
throw e;
} catch (Throwable erro) {
error.addError(erro);
}
}
if (keyStore == null && error.hasErrors()) {
throw error;
}
return keyStore;
}
@Override
public void setCallbackHandler(CallbackHandler callback) {
this.callback = callback;
}
}